// error

// Rust将错误分为两大类，可恢复的和不可恢复的
//     可恢复的错误通常代表向用户报告错误和重试操作是合理的情况 使用Result
//     不可恢复的错误，如尝试访问超过数组结尾的位置 使用panic!


// 不可恢复
// fn main() {
//     panic!("crash and burn");
// }

// 可恢复
enum Result<T, E> {
    Ok(T),
    Err(E),
}
// T和E是泛型类型参数，T代表成功是返回的Ok成员中的数据类型，E代表失败是返回的Err成员中的错误的类型。

use std::fs::File;
fn main() {
    let f = File::open("hello.txt");
    let _r = match f {
        Ok(file) => {
            file
        },
        Err(error) => {
            panic!("Problem opening the file: {:?}", error)
        }
    };
}

// 对于返回Result类型的函数，不用总是使用match去匹配结果，
// 还可以使用简写获取到Result<T, E>中的T类型，不过使用简写时，
// 当Result<T, E>是Err时程序会panic：

// 使用unwrap
use std::fs::File;
fn main() {
    let f = File::open("hello.txt").unwrap();   //使用unwrap简写来获取到Result中的T类型，
    //当hello.txt打开失败时程序会panic
}

// 使用except
fn main() {
    //使用unwrap简写来获取到Result中的T类型，
    //当hello.txt打开失败时程序会panic
    let greeting_file = File::open("hello.txt")
        .expect("hello.txt should be included in this project");
}

// 传播错误
// 除了函数中处理错误外，还可以选择让调用者知道这个错误并决定如何处理，这叫做传播错误。
fn produce_error(switch: bool) -> Result<(), &'static str> {
    if switch {
        return Err("This is a error");
    }
    Ok(())
}


// fn transmit_error(flag: bool) -> Result<String, &'static str> {
//     produce_error(flag)?;   // 如果调用produce_error函数返回的是Err类型将会直接从此行返回
//
//     println!("如果produce_error函数返回的是错误将不会执行到这里");
//     Ok("Hello".to_string())
// }


fn transmit_error(flag: bool) -> Result<String, &'static str> {
    let s = produce_error(flag);
    match s {
        Ok(_) => return Ok("Hello".to_string()),
        Err(e) => return Err(e),
    }
}

// fn read_username_from_file() -> Result {
//     let mut s = String::new();
//     //如果open()失败将直接把“打开失败错误”返回，如果read_to_string失败也将把“读取失败错误”返回
//     File::open("hello.txt")?.read_to_string(&mut s)?;
//     Ok(s)
// }

// ？运算符被用于返回Result的函数，Result返回的是Err类型，则直接结束将错误传播到上一级。

fn main() {
    let result = transmit_error(true);

    match result {
        Ok(_) => {
            println!("There is no error!");
        }
        Err(e) => {
            println!("Error is: {:?}", e);
        }
    }
}